/*
Copyright (C) 2009 Matthew Perry

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This libary/program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using BaseTools.Configuration;
using BaseTools.Searching;
using System.Collections.Generic;
using System.Diagnostics;
using BaseTools.Helpers;

namespace BaseTools.XS
{
	/// <summary>
	/// Application location storage with XConf
	/// </summary>
	public class AppLocator
	{
		/// <summary>
		/// The file relative to XConf where application locator settings are stored
		/// </summary>
		public const string APPFILE = "applocator.xbt";
		
		/// <summary>
		/// Set the application info
		/// </summary>
		/// <param name="app">The application name</param>
		/// <param name="appinfo">The app info of the application</param>
		public static void SetAppInfo(string app, AppInfo appinfo)
		{
			ConfigList lst = XConf.LoadConfig(APPFILE), pancakes;
			
			if (lst.HasSection(new StringValidator(app)))
			{
				pancakes = lst.GetSection(app);
				pancakes.SetString("Location", appinfo.Location);
				pancakes.RemoveKey("Commands");
				pancakes.AddSection("Commands", GenericConverter.WriteSection(appinfo.Commands));
			}
			else
			{
				pancakes = new ConfigList();
				pancakes.AddString("Location", appinfo.Location);
				pancakes.AddSection("Commands", GenericConverter.WriteSection(appinfo.Commands));
				lst.AddSection(app, pancakes);
			}
			
			XConf.SaveConfig(APPFILE, lst);
			
		}
		
		/// <summary>
		/// Get the application info
		/// </summary>
		/// <param name="app">The application name</param>
		/// <returns>The AppInfo of the appplication or null if none is found</returns>
		public static AppInfo GetAppInfo(string app)
		{
			ConfigList pancakes = XConf.LoadConfig(APPFILE), sandvich;
			sandvich = pancakes.GetSection(app);
			
			if (sandvich != null)
			{
				return new AppInfo(sandvich["Location"], GenericConverter.ReadSection(sandvich.GetSection("Commands")));
			}
			else
			{
				return null;
			}
		}
		
		/// <summary>
		/// Application operator accessor
		/// </summary>
		public static PropAppInfo Info
		{
			get
			{
				return new PropAppInfo();
			}
		}
		
		/// <summary>
		/// Create format using a ConfigList, very useful for command line
		/// </summary>
		/// <param name="Data">The original formatted string</param>
		/// <param name="Variables">The ConfigList of variables</param>
		/// <returns></returns>
		public static string CreateFormat(string Data, ConfigList Variables)
		{
			return CreateFormat(Data, GenericConverter.ReadSection(Variables));
		}
		
		/// <summary>
		/// Create format using a Dictionary, very useful for command line
		/// </summary>
		/// <param name="Data">The original formatted string</param>
		/// <param name="Variables">The dictionary of variables</param>
		/// <returns></returns>
		public static string CreateFormat(string Data, Dictionary<string, string> Variables)
		{
			// Adapted from VB6 Doom BuilderX (added by Doomguy0505/Scent Tree)
			// It was used for the same purpose as it is now, command line variable replacement
			// This is a printf and dos hybrid %varname% and %% formatting
			
			// Data is the data to be processed (duh)
			// Variables are the variables that are processed
			// EnableEscaped is used when characters can't be used (this is from a vb course that used an ini, _
			// but clsConfiguration supports character escaping
			// %% represents a % sign, similar to C's printf function
			
			string RetVal, VarName;
			bool InEscape;
			char CurChar;
			bool InVar;
			InEscape = false;
			InVar = false;
			RetVal = "";
			VarName = "";
			
			for(int i=0;i<Data.Length;i++)
			{
				CurChar = Data[i];
				if (InEscape)
				{
					switch(CurChar)
					{
						case 'n':
							RetVal += '\n';
							break;
						case 'r':
							RetVal += '\r';
							break;
						case 't':
							RetVal += '\t';
							break;
						default:
							RetVal += CurChar;
							break;
					}
					InEscape = false;
				}
				else
				{
					if (CurChar == '^')
					{
						InEscape = true;
					}
					else if (CurChar == '%')
					{
						if (InVar)
						{
							if (VarName.Length == 0)
							{
								RetVal += "%";
							}
							else if (Variables.ContainsKey(VarName))
							{
								RetVal += Variables[VarName];
							}
							VarName = "";

							InVar = false;
						}
						else
						{
							InVar = true;
						}
					}
					else if (InVar)
					{
						VarName += CurChar;
					}
					else
					{
						RetVal += CurChar;
					}
				}
			}
			return RetVal;
		}
		
		
		/// <summary>
		/// AppInfo operator
		/// </summary>
		public class PropAppInfo
		{
			/// <summary>
			/// Get/SetAppInfo operator
			/// </summary>
			public AppInfo this[string app]
			{
				get
				{
					return GetAppInfo(app);
				}
				set
				{
					SetAppInfo(app, value);
				}
			}
		}
		
		/// <summary>
		/// Gets the ProcessStartInfo for an application
		/// </summary>
		/// <param name="app">The application name</param>
		/// <returns>The PSI of the app or null if none found</returns>
		public static ProcessStartInfo GetStartInfo(string app)
		{
			AppInfo appi = GetAppInfo(app);
			
			if (appi != null)
			{
				return new ProcessStartInfo(appi.Location);
			}
			else
			{
				return null;
			}
		}
		
		/// <summary>
		/// Gets the ProcessStartInfo for an application
		/// </summary>
		/// <param name="app">The application name</param>
		/// <param name="command">The command line index to use</param>
		/// <returns></returns>
		public static ProcessStartInfo GetStartInfo(string app, string command)
		{
			AppInfo appi = GetAppInfo(app);
			
			if (appi != null)
			{
				string cmd = "";
				if (appi.Commands.ContainsKey(command))
					cmd = appi.Commands[command];
				return new ProcessStartInfo(appi.Location, cmd);
			}
			else
			{
				return null;
			}
		}
		
		/// <summary>
		/// Gets the ProcessStartInfo for an application using CreateFormat
		/// </summary>
		/// <param name="app">The application name</param>
		/// <param name="command">The command line index to use</param>
		/// <param name="vars">The variables list</param>
		/// <returns></returns>
		public static ProcessStartInfo GetStartInfo(string app, string command, Dictionary<string, string> vars)
		{
			AppInfo appi = GetAppInfo(app);
			
			if (appi != null)
			{
				string cmd = "";
				if (appi.Commands.ContainsKey(command))
					cmd = CreateFormat(appi.Commands[command], vars);
				return new ProcessStartInfo(appi.Location, cmd);
			}
			else
			{
				return null;
			}
		}
	}
}
